﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Rhino.Mocks;
using Rhino.Mocks.Interfaces;

using SharedGenomics.Workbench.Views;
using SharedGenomics.Workbench.PresentationModel;
using SharedGenomics.Workbench.Presenters;

namespace SharedGenomics.Workbench.Tests.Presenters
{
    [TestClass]
    public class CategoryFilterPresenterTests
    {
        private MockRepository mocks;
        private ICategoryFilterView view;
        private CategoryValueViewFactory valueViewFactory;
        IEnumerable<ValueDisplayItem<string>> categories;
        Func<string, IEnumerable<ValueDisplayItem<string>>> categoryValuesFunc;

        private string lastCategoryValuesFuncArgument;

        [TestInitialize]
        public void Setup()
        {
            this.mocks = new MockRepository();

            this.view = this.mocks.Stub<ICategoryFilterView>();
            this.valueViewFactory = this.mocks.Stub<CategoryValueViewFactory>();
            this.categories = new[] { new ValueDisplayItem<string>("gender", "Gender"), new ValueDisplayItem<string>("ethnic", "Ethnicity") };

            this.categoryValuesFunc = new Func<string, IEnumerable<ValueDisplayItem<string>>>(s => {
                this.lastCategoryValuesFuncArgument = s;
                return new ValueDisplayItem<string>[] { };
            });
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorTest_Invalid_ViewNull()
        {
            var presenter = new CategoryFilterPresenter(null, this.valueViewFactory, this.categories, this.categoryValuesFunc);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorTest_Invalid_ValueViewFactoryNull()
        {
            var presenter = new CategoryFilterPresenter(this.view, null, this.categories, this.categoryValuesFunc);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorTest_Invalid_ValuesFuncNull()
        {
            var presenter = new CategoryFilterPresenter(this.view, this.valueViewFactory, this.categories, null);
        }

        [TestMethod]
        public void ConstructorTest_RegistersForViewEvents()
        {
            this.view = this.mocks.DynamicMock<ICategoryFilterView>();

            using (this.mocks.Record())
            {
                this.view.RemoveClicked += null;
                LastCall.IgnoreArguments();

                this.view.SelectedCategoryChanged += null;
                LastCall.IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                var presenter = new CategoryFilterPresenter(this.view, this.valueViewFactory, this.categories, this.categoryValuesFunc);
            }
        }

        [TestMethod]
        public void RemoveClickedTest_RaisesFilterRemovedEvent()
        {
            this.view.RemoveClicked += null;
            IEventRaiser removeEvent = LastCall.IgnoreArguments().GetEventRaiser();

            this.mocks.ReplayAll();
            var presenter = this.CreatePresenter();

            bool eventRaised = false;
            presenter.FilterRemoved += (o, e) => { eventRaised = true; };

            removeEvent.Raise(null, null);
            Assert.IsTrue(eventRaised);
        }

        [TestMethod]
        public void RemoveClickedTest_PresenterDeregistersViewEvents()
        {
            this.view = this.mocks.DynamicMock<ICategoryFilterView>();
            IEventRaiser removeEvent;

            using (this.mocks.Record())
            {
                this.view.RemoveClicked -= null;
                LastCall.IgnoreArguments();
                removeEvent = LastCall.GetEventRaiser();

                this.view.SelectedCategoryChanged -= null;
                LastCall.IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                var presenter = this.CreatePresenter();
                removeEvent.Raise(null, null);
            }
        }

        [TestMethod]
        public void SelectedCategoryChangedTest_ReloadsAvailableViewValues()
        {
            this.view = this.mocks.DynamicMock<ICategoryFilterView>();
            IEventRaiser changedEvent;

            using (this.mocks.Record())
            {
                this.view.SelectedCategoryChanged += null;
                changedEvent = LastCall.IgnoreArguments().GetEventRaiser();

                SetupResult.For(this.view.SelectedCategory).Return("gender");
                this.view.AvailableCategories = null;
                LastCall.IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                var presenter = this.CreatePresenter();
                changedEvent.Raise(null, null);

                Assert.AreEqual("gender", this.lastCategoryValuesFuncArgument);
            }
        }

        private CategoryFilterPresenter CreatePresenter()
        {
            return new CategoryFilterPresenter(this.view, this.valueViewFactory, this.categories, this.categoryValuesFunc);
        }
    }
}
